package LinkList;

/*
复制带随机指针的链表
给你一个长度为 n 的链表，每个节点包含一个额外增加的随机指针 random ，该指针可以指向链表中的任何节点或空节点。
构造这个链表的深拷贝。深拷贝应该正好由 n 个 全新 节点组成，其中每个新节点的值都设为其对应的原节点的值。
新节点的 next 指针和 random 指针也都应指向复制链表中的新节点，并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如，如果原链表中有 X 和 Y 两个节点，其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ，同样有 x.random --> y 。
返回复制链表的头节点。
用一个由n个节点组成的链表来表示输入/输出中的链表。每个节点用一个[val, random_index]表示：
val：一个表示Node.val的整数。
random_index：随机指针指向的节点索引（范围从0到n-1）；如果不指向任何节点，则为null。
你的代码 只 接受原链表的头节点 head 作为传入参数。

示例 1：
输入：head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出：[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2：
输入：head = [[1,1],[2,1]]
输出：[[1,1],[2,1]]
示例 3：
输入：head = [[3,null],[3,0],[3,null
作者：LeetCode
链接：https://leetcode.cn/leetbook/read/linked-list/fdi26/
 */

import java.util.HashMap;

public class _54复制带随机指针的链表 {
    public static void main(String[] args) {

    }

    class Node {
        int val;
        Node next;
        Node random;

        public Node(int val) {
            this.val = val;
            this.next = null;
            this.random = null;
        }
    }

    //官解方法一：回溯 + 哈希表
    class Solution {
        HashMap<Node, Node> map = new HashMap<>();
        public Node copyRandomList(Node head) {
            if (head == null) {
                return null;
            }
            if (!map.containsKey(head)) {
                Node newHead = new Node(head.val);
                map.put(head, newHead);
                newHead.next = copyRandomList(head.next);
                newHead.random = copyRandomList(head.random);
            }
            //返回head键的值
            return map.get(head);
        }
    }

    //方法二：迭代 + 节点拆分
    //思路及算法
    //注意到方法一需要使用哈希表记录每一个节点对应新节点的创建情况，而我们可以使用一个小技巧来省去哈希表的空间。
    //我们首先将该链表中每一个节点拆分为两个相连的节点，例如对于链表 A→B→C，我们可以将其拆分为 A→A′→B→B ′→C→C ′。
    //对于任意一个原节点 S，其拷贝节点 S ′即为其后继节点。
    //这样，我们可以直接找到每一个拷贝节点 S ′的随机指针应当指向的节点，即为其原节点 S 的随机指针指向的节点 T 的后继节点 T′ 。
    //需要注意原节点的随机指针可能为空，我们需要特别判断这种情况。
    //当我们完成了拷贝节点的随机指针的赋值，我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可，只需要遍历一次。
    //同样需要注意最后一个拷贝节点的后继节点为空，我们需要特别判断这种情况。

        public Node copyRandomList(Node head) {
            if (head == null) {
                return null;
            }
            for (Node node = head; node != null; node = node.next.next) {
                Node nodeNew = new Node(node.val);
                nodeNew.next = node.next;
                node.next = nodeNew;
            }
            for (Node node = head; node != null; node = node.next.next) {
                Node nodeNew = node.next;
                nodeNew.random = (node.random != null) ? node.random.next : null;
            }
            Node headNew = head.next;
            for (Node node = head; node != null; node = node.next) {
                Node nodeNew = node.next;
                node.next = node.next.next;
                nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
            }
            return headNew;
        }

}
